home *** CD-ROM | disk | FTP | other *** search
/ TPUG - Toronto PET Users Group / TPUG Users Group CD / TPUG Users Group CD.iso / AMIGA / AMICUS / AMICUS18.ADF / Games / Decay / dk.mod < prev    next >
Text File  |  1989-01-27  |  12KB  |  412 lines

  1.  
  2.                                                                                                                                                                                                                                  (*$Q*)                              
  3. MODULE DK;
  4.  
  5. (* A little fun, inspired by Leo Schwab's TILT *)
  6.  
  7. (* Author: Thomas H. Handel, PeopleLink ID -- THH -- *)
  8.  
  9. (* I'm still learning Modula-2 and programming on Amy, so this may not
  10.    be the tidiest or best way to do what the program does.  Also, it is
  11.    probably not the most elegant example of structured programming ever
  12.    created.  Finally, I am certain that there are many enhancements that 
  13.    more experienced programmers will be able to add (like maybe a close 
  14.    gadget and the wherewithall to respond to it).  Please fiddle at will.     If you have comments or suggestions, please contact me on PeopleLink or    by U.S. Snail at:
  15.  
  16.    628 Harberts Ct.
  17.    Annapolis, MD 21401
  18.  
  19.    Thanks in advance. *)
  20.  
  21. (* Placed in the Public Domain, 29 March 1987 *)
  22.  
  23. FROM SYSTEM IMPORT ADR, BYTE, NULL;
  24. FROM Intuition IMPORT NewWindow, WindowPtr, IntuitionName, IntuitionBase,
  25.                       WindowFlags, WindowFlagSet, IDCMPFlagSet,
  26.                       CloseWindowFlag, ScreenFlagSet, WBenchScreen,
  27.                       SmartRefresh,IntuiMessagePtr;
  28. FROM Libraries IMPORT OpenLibrary, CloseLibrary;
  29. FROM Windows IMPORT OpenWindow, CloseWindow;
  30. FROM Strings IMPORT String;
  31. FROM Pens IMPORT ReadPixel, WritePixel, SetAPen;
  32. FROM GraphicsLibrary IMPORT GraphicsName, GraphicsBase;
  33. FROM Ports IMPORT GetMsg, ReplyMsg, MessagePtr;
  34. FROM Rasters IMPORT RastPortPtr;
  35. FROM Storage IMPORT ALLOCATE, DEALLOCATE;
  36. FROM RandomNumbers IMPORT Random;
  37.  
  38. VAR WPtr: WindowPtr;
  39.     NWin: NewWindow;
  40.     WNam: String;
  41.     RprtPtr: RastPortPtr;
  42.     MsgPtr : IntuiMessagePtr;
  43.  
  44.  
  45.  
  46. PROCEDURE Initialize(): BOOLEAN;  (* Open the libraries *)
  47.  
  48. BEGIN
  49.    IntuitionBase := OpenLibrary(IntuitionName,0);
  50.    GraphicsBase := OpenLibrary(GraphicsName,0);
  51.    IF ((IntuitionBase = 0) OR (GraphicsBase = 0)) THEN RETURN FALSE
  52.       ELSE RETURN TRUE;
  53.    END;
  54. END Initialize;
  55.  
  56.  
  57. PROCEDURE InitWindow;  (* Set up and open the window *)
  58.  
  59. BEGIN
  60.    WNam := "DK!";
  61.    WITH NWin DO
  62.       LeftEdge := 450;
  63.       TopEdge := 0;
  64.       Width := 100;
  65.       Height := 10;
  66.       DetailPen := BYTE(0);
  67.       BlockPen := BYTE(1);
  68.       IDCMPFlags := IDCMPFlagSet{CloseWindowFlag};
  69.       Flags := SmartRefresh + WindowFlagSet{Activate, WindowClose,
  70.                WindowDepth};
  71.       FirstGadget := NULL;
  72.       CheckMark := NULL;
  73.       Title := ADR(WNam);
  74.       Screen := NULL;
  75.       BitMap := NULL;
  76.       MinWidth := 0;
  77.       MinHeight := 0;
  78.       MaxWidth := 0;
  79.       MaxHeight := 0;
  80.       Type := ScreenFlagSet{WBenchScreen};
  81.    END;
  82.    WPtr := OpenWindow(NWin);
  83. END InitWindow;
  84.  
  85.  
  86. PROCEDURE Decay; (* Erode the display *)
  87.  
  88.    TYPE ColNodePtr = POINTER TO ColNode;
  89.         ColNode = RECORD
  90.                     Col  : CARDINAL;  (* X-value of column *)
  91.                     Row  : CARDINAL;  (* Y-value of next non-zero pixel *)
  92.                     PClr : CARDINAL;  (* Pixel Pen number *)
  93.                     Next : ColNodePtr;  (* Forward pointer *)
  94.                     Prev : ColNodePtr  (* Backward pointer *)
  95.                   END;
  96.         PixlNodePtr = POINTER TO PixlNode;
  97.         PixlNode = RECORD
  98.                      PClr : CARDINAL; (* Pixel color *)
  99.                      CurX : CARDINAL; (* Current location, X-value *)
  100.                      CurY : CARDINAL; (* Current location, Y-value *)
  101.                      Next : PixlNodePtr; (* Forward pointer *)
  102.                      Prev : PixlNodePtr (* Backward pointer *)
  103.                    END;
  104.  
  105.    VAR ScrnTop   : CARDINAL;  (* Screen top *)
  106.        TopEdge   : CARDINAL;  (* Screen top less title bar *)
  107.        Bottom    : CARDINAL;  (* Screen bottom less border *)
  108.        YStrt     : CARDINAL;  (* Four pixels above bottom *)
  109.        ColCount  : CARDINAL;  (* Number of ColNodes in list *)
  110.        ColHead   : ColNodePtr; (* Pointer to head of ColNode list *)
  111.        CPtr      : ColNodePtr; (* Utility pointer for list traversal *)
  112.        PixlCount : CARDINAL;  (* Number of PixlNodes in list *)
  113.        PixlHead  : PixlNodePtr; (* Pointer to head of PixlNode list *)
  114.        PPtr      : PixlNodePtr; (* Utility pointer for list traversal *)
  115.        Depth     : ARRAY [2..637] OF CARDINAL; (* Depth of snow by col *)
  116.  
  117.  
  118.    PROCEDURE ComputeParms;  (* Get some basic parameters *)
  119.  
  120.    BEGIN
  121.       ScrnTop := WPtr^.WScreen^.TopEdge;
  122.       TopEdge := ScrnTop + 10;
  123.       Bottom := CARDINAL(WPtr^.WScreen^.Height) + ScrnTop - 1;
  124.       YStrt := Bottom - 4;
  125.    END ComputeParms;
  126.  
  127.  
  128.    PROCEDURE InitVars;  (* Initialize Variables *)
  129.  
  130.    VAR I : INTEGER; (* Counter *)
  131.  
  132.    BEGIN
  133.       FOR I := 2 TO 637 DO
  134.          Depth[I] := 0
  135.       END;
  136.       RprtPtr := ADR(WPtr^.WScreen^.RPort);
  137.       ColCount := 0;
  138.       PixlCount := 0;
  139.       ColHead := NIL;
  140.       PixlHead := NIL
  141.    END InitVars;
  142.  
  143.  
  144.    PROCEDURE FindCols;  (* Create list of cols containing non-zero pixls *)
  145.    VAR X    : CARDINAL; (* Column Counter *)
  146.        Y    : CARDINAL; (* Row Counter *)
  147.        Pixl : CARDINAL; (* Pen number of pixel *)
  148.  
  149.    BEGIN
  150.       FOR X := 2 TO 637 DO
  151.          Y := YStrt;
  152.          LOOP
  153.             Pixl := ReadPixel(RprtPtr,X,Y);
  154.             IF Pixl <> 0 THEN
  155.                NEW (CPtr);            (* Create node for list *)
  156.                CPtr^.Col := X;
  157.                CPtr^.Row := Y;
  158.                CPtr^.PClr := Pixl;
  159.                IF ColHead = NIL THEN  (* and link it in at head of list *)
  160.                   CPtr^.Next := NIL;
  161.                   CPtr^.Prev := NIL
  162.                ELSE
  163.                   CPtr^.Next := ColHead;
  164.                   CPtr^.Prev := NIL;
  165.                   ColHead^.Prev := CPtr
  166.                END;
  167.                ColHead := CPtr;
  168.                CPtr := NIL;
  169.                INC(ColCount);
  170.                EXIT
  171.             END;
  172.             Y := Y - 1;
  173.             IF Y <= TopEdge THEN
  174.                EXIT
  175.             END
  176.          END
  177.       END;
  178.    END FindCols;
  179.  
  180.  
  181.    PROCEDURE NewPixel;  (* Get a new pixel at random for snowflake ops *)
  182.  
  183.    VAR RNum : CARDINAL;  (* Random Number *)
  184.        I    : CARDINAL;  (* Counter *)
  185.        Pixl : CARDINAL;  (* Pen number of pixel *)
  186.  
  187.  
  188.       PROCEDURE DeleteCol;  (* Remove an empty column from the list *)
  189.  
  190.       BEGIN
  191.          IF CPtr = ColHead THEN
  192.             IF CPtr^.Next <> NIL THEN
  193.                ColHead := ColHead^.Next;
  194.                ColHead^.Prev := NIL
  195.             ELSE
  196.                ColHead := NIL
  197.             END
  198.          ELSE
  199.             IF CPtr^.Next = NIL THEN
  200.                CPtr^.Prev^.Next := NIL
  201.             ELSE
  202.                CPtr^.Prev^.Next := CPtr^.Next;
  203.                CPtr^.Next^.Prev := CPtr^.Prev
  204.             END
  205.          END;
  206.          DISPOSE (CPtr);
  207.          ColCount := ColCount - 1;
  208.       END DeleteCol;
  209.  
  210.  
  211.    BEGIN  (* NewPixel *)
  212.       RNum := Random(ColCount - 1);     (* 0 <= RNum <= [ColCount-1] *)
  213.       CPtr := ColHead;
  214.       IF RNum > 0 THEN
  215.          FOR I := 0 TO RNum DO
  216.             CPtr := CPtr^.Next
  217.          END
  218.       END;
  219.       NEW (PPtr);
  220.       PPtr^.PClr := CPtr^.PClr;
  221.       PPtr^.CurX := CPtr^.Col;
  222.       PPtr^.CurY := CPtr^.Row;
  223.       IF PixlHead = NIL THEN
  224.          PPtr^.Next := NIL;
  225.          PPtr^.Prev := NIL
  226.       ELSE
  227.          PPtr^.Next := PixlHead;
  228.          PPtr^.Prev := NIL;
  229.          PixlHead^.Prev := PPtr
  230.       END;
  231.       PixlHead := PPtr;
  232.       INC(PixlCount);
  233.       LOOP
  234.          CPtr^.Row := CPtr^.Row - 1;
  235.          IF CPtr^.Row < TopEdge THEN
  236.             DeleteCol;
  237.             EXIT
  238.          ELSE
  239.             Pixl := ReadPixel(RprtPtr,CPtr^.Col,CPtr^.Row);
  240.             IF Pixl <> 0 THEN
  241.                CPtr^.PClr := Pixl;
  242.                EXIT 
  243.             END
  244.          END
  245.       END;
  246.    END NewPixel;
  247.  
  248.  
  249.    PROCEDURE MovePixels;  (* Make the snow fall *)
  250.  
  251.    VAR XDest : CARDINAL;  (* Pixel destination, X-value *)
  252.        YDest : CARDINAL;  (* Pixel destination, Y-value *)
  253.        DFlag : BOOLEAN;  (* Signals pixel ready for deletion from list *)
  254.        RLFlag: BOOLEAN;  (* Direction of snow drift *)
  255.  
  256.  
  257.       PROCEDURE DeletePixel;  (* Remove a pixel from the list *)
  258.  
  259.       VAR tPtr : PixlNodePtr;  (* Utility pointer *)
  260.  
  261.       BEGIN
  262.          tPtr := PPtr;
  263.          IF PPtr = PixlHead THEN
  264.             IF PPtr^.Next <> NIL THEN
  265.                PixlHead := PixlHead^.Next;
  266.                PixlHead^.Prev := NIL
  267.             ELSE
  268.                PixlHead := NIL
  269.             END;
  270.             tPtr := PPtr;
  271.             PPtr := PixlHead
  272.          ELSE
  273.             IF PPtr^.Next = NIL THEN
  274.                PPtr^.Prev^.Next := NIL
  275.             ELSE
  276.                PPtr^.Prev^.Next := PPtr^.Next;
  277.                PPtr^.Next^.Prev := PPtr^.Prev
  278.             END;
  279.             tPtr := PPtr;
  280.             PPtr := PPtr^.Prev
  281.          END;
  282.          DISPOSE (tPtr);
  283.          PixlCount := PixlCount - 1;
  284.          DFlag := FALSE;
  285.       END DeletePixel;
  286.  
  287.  
  288.       PROCEDURE ComputeDest;  (* Compute a random destination for pixel *)
  289.  
  290.       BEGIN
  291.          XDest := PPtr^.CurX + 8 - Random(16);
  292.          YDest := PPtr^.CurY + Random(13);
  293.          IF XDest <= 2 THEN
  294.             XDest := 3 + Random(5)
  295.          END;
  296.          IF XDest >= 637 THEN
  297.             XDest := 636 - Random(5)
  298.          END;
  299.          IF YDest > Bottom - Depth[XDest] THEN
  300.             YDest := Bottom - Depth[XDest];
  301.             DFlag := TRUE
  302.          END;
  303.       END ComputeDest;
  304.  
  305.  
  306.       PROCEDURE Drift;  (* Keep the snow from stacking up in tall towers *)
  307.       VAR ChgFlag : BOOLEAN;  (* Flags change in XDest *)
  308.  
  309.  
  310.          PROCEDURE CheckLeft;  (* See if flake should drift left *)
  311.  
  312.          BEGIN
  313.             IF Depth[XDest] > Depth[XDest-1] THEN
  314.                XDest := XDest - 1;
  315.                ChgFlag := TRUE
  316.             END
  317.          END CheckLeft;
  318.  
  319.  
  320.          PROCEDURE CheckRight;  (* See if flake should drift right *)
  321.  
  322.          BEGIN
  323.             IF Depth[XDest] > Depth[XDest+1] THEN
  324.                INC(XDest);
  325.                ChgFlag := TRUE
  326.             END
  327.          END CheckRight;
  328.  
  329.       BEGIN (* Drift *)
  330.          ChgFlag := TRUE;
  331.          WHILE (XDest > 2) AND (XDest < 637) AND (ChgFlag) DO
  332.             ChgFlag := FALSE;
  333.             IF RLFlag THEN
  334.                CheckLeft;
  335.                CheckRight
  336.             ELSE
  337.                CheckRight;
  338.                CheckLeft
  339.             END;
  340.             YDest := Bottom - Depth[XDest] - 1
  341.          END
  342.       END Drift;
  343.  
  344.  
  345.       PROCEDURE MoveOne;  (* Move one pixel to new destination *)
  346.  
  347.       BEGIN
  348.          SetAPen(RprtPtr,0);
  349.          WritePixel(RprtPtr,PPtr^.CurX,PPtr^.CurY);
  350.          SetAPen(RprtPtr,PPtr^.PClr);
  351.          WritePixel(RprtPtr,XDest,YDest);
  352.          PPtr^.CurX := XDest;
  353.          PPtr^.CurY := YDest;
  354.       END MoveOne;
  355.  
  356.    BEGIN (* MovePixels *)
  357.       RLFlag := TRUE;
  358.       DFlag := FALSE;
  359.       PPtr := PixlHead;
  360.       WHILE PPtr <> NIL DO           (* While there are still flakes *)
  361.          ComputeDest;                (* Find this one a new destination *)
  362.          IF DFlag THEN               (* If it has landed *)
  363.             Drift;                   (* See if it should roll R or L *)
  364.             RLFlag := NOT(RLFlag)
  365.          END;
  366.          MoveOne;                    (* Actually move it to new dest *)
  367.          IF DFlag THEN               (* If it has landed *)
  368.             INC(Depth[XDest]);       (* increment depth in column *)
  369.             DeletePixel              (* and remove pixel from list *)
  370.          END;
  371.          IF PPtr <> NIL THEN
  372.             PPtr := PPtr^.Next
  373.          END
  374.       END
  375.    END MovePixels;
  376.    PROCEDURE DanceOff;  (* Clean things up *)
  377.  
  378.    BEGIN
  379.       CloseWindow(WPtr);
  380.       CloseLibrary(IntuitionBase);
  381.       CloseLibrary(GraphicsBase);
  382.    END DanceOff;
  383.  
  384. BEGIN (* Decay *)
  385.    ComputeParms;
  386.    InitVars;
  387.    FindCols;
  388.    REPEAT
  389.       IF ColCount <> 0 THEN  
  390.          NewPixel
  391.       END;
  392.       IF PixlCount <> 0 THEN
  393.          MovePixels
  394.       END;
  395.    MsgPtr := GetMsg(WPtr^.UserPort);
  396.    IF MsgPtr <> NULL THEN
  397.       ColCount := 0;
  398.       PixlCount := 0;
  399.       ReplyMsg (MessagePtr(MsgPtr));
  400.    END;
  401.    UNTIL (ColCount = 0) AND (PixlCount = 0);
  402.    DanceOff;
  403. END Decay;
  404.  
  405.  
  406. BEGIN (* DK *)
  407.    IF Initialize() THEN
  408.      InitWindow;
  409.      Decay;
  410.    END;
  411. END DK.
  412.